﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "TaskGraph.generated.h"

/**	TaskGraph
 * 模块构成
 *		自定义的任务必须要满足 TGraphTask 中对 Task 的接口需求
 *			构造函数可以传参，最好不要使用引用类型，会有”悬空引用“的风险，可以使用指针来代替引用
 *			GetStatId() 固定写法，函数内传入自定义TaskGraph类型
 *			GetDesiredThread() 指定在哪个线程运行,也可以通过 FAutoConsoleTaskPriority 对象获取合适的线程
 *			GetSubsequentsMode() 后续执行模式，因为可以有子任务
 *				ESubsequentsMode::TrackSubsequents 存在后续任务，实际没有后续任务也不影响，常用该类型
 *				ESubsequentsMode::FireAndForget 没有后续任务
 *			DoTask() 线程逻辑执行函数
 *		任务的创建
 *			TGraphTask<T> 是模板类，可以指定自定义任务的类型
 *			CreateTask()
 *				第一个参数 Prerequisites
 *					用来指定该任务依赖的事件数组，默认为 NULL.
 *					在所有依赖事件都触发后，该任务才会放到任务队列里面分配给线程执行。
 *				第二个参数 ENamedThreads::Type
 *					用来指定线程类型
 *				// 完整函数为
 *				static FConstructor CreateTask(const FGraphEventArray* Prerequisites = NULL, ENamedThreads::Type CurrentThreadIfKnown = ENamedThreads::AnyThread) 
 *			ConstructAndDispatchWhenReady()
 *				创建任务后立即执行
 *				调用创建的TaskGraph类型（本例中为FTaskGraph_SimpleTask）的构造函数
 *				可以传递构造函数的参数，进行初始化
 *			ConstructAndHold()
 *				创建任务后挂起，等待 unlock() 唤醒任务执行
 *				参数同上
 **/
DECLARE_DELEGATE_OneParam(FGraphTaskDelegate, const FString&); // 单播委托

USTRUCT(BlueprintType)
struct FTaskGraphItem
{
	// 结构体用来传参
	GENERATED_USTRUCT_BODY()
public:
	UPROPERTY(BlueprintReadWrite)
	FString m_ThreadName; // 线程名称

	FGraphEventRef m_GraphEventRef; // 自动执行的任务
	TGraphTask<class FTaskGraphWithPrerequisitesAndChild>* m_GraphTask; // 需要触发执行的任务

	// 构造函数
	FTaskGraphItem(FString ThreadName = TEXT("None"), FGraphEventRef GraphEventRef = nullptr, TGraphTask<class FTaskGraphWithPrerequisitesAndChild>* GraphTask = nullptr) : m_ThreadName(ThreadName), m_GraphEventRef(GraphEventRef), m_GraphTask(GraphTask) {}

	~FTaskGraphItem()
	{
		m_GraphEventRef = nullptr;
		m_GraphTask = nullptr;
	}
};

class FTaskGraph_SimpleTask // 作为具体执行的任务
{
	FString m_ThreadName;
	FGraphTaskDelegate m_GraphTaskDelegate;

public:
	FTaskGraph_SimpleTask(const FString& ThreadName, FGraphTaskDelegate GraphTaskDelegate) : m_ThreadName(ThreadName), m_GraphTaskDelegate(GraphTaskDelegate) {}
	~FTaskGraph_SimpleTask() {}

	// 固定写法
	FORCEINLINE TStatId GetStatId() const
	{
		RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph_SimpleTask, STATGROUP_TaskGraphTasks);
	}

	// 指定在主线程，因为用到 AActor 蓝图里的函数
	static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::GameThread; }

	// 后续执行模式
	static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }

	// 线程逻辑执行函数
	void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
	{
		check(IsInGameThread()); //确认是否在主线程
		FString message = FString::Printf(TEXT("SimpleTaskTask[%s] execute the GraphTaskDelegate!"), *m_ThreadName);
		m_GraphTaskDelegate.ExecuteIfBound(message);
		// UE_LOG(LogTemp, Warning, TEXT("SimpleTaskTask[%s] execute!"), *m_ThreadName);
	}
};

class FTaskGraphWithPrerequisitesAndChild // 作为通用任务，可作为依赖事件的任务，也可作为子任务
{
	FString m_ThreadName;
	TArray<TGraphTask<FTaskGraphWithPrerequisitesAndChild>*> m_ChildGraphTask; // 子任务数组
	FGraphTaskDelegate m_GraphTaskDelegate; // 单播委托

public:
	// 构造函数
	FTaskGraphWithPrerequisitesAndChild(const FString& ThreadName, const TArray<TGraphTask<FTaskGraphWithPrerequisitesAndChild>*>& ChildTask, FGraphTaskDelegate GraphTaskDelegate) : m_ThreadName(ThreadName), m_ChildGraphTask(ChildTask), m_GraphTaskDelegate(GraphTaskDelegate) {}

	~FTaskGraphWithPrerequisitesAndChild() {}

	// 固定写法
	FORCEINLINE TStatId GetStatId() const
	{
		RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraphWithPrerequisitesAndChild, STATGROUP_TaskGraphTasks);
	}

	// 指定在哪个线程运行
	static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; }

	// 后续执行模式
	static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }

	// 线程逻辑执行函数
	void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
	{
		// UE_LOG(LogTemp, Warning, TEXT("Task[%s] Begin!"), *m_ThreadName);
		// 执行子任务，此处通用任务作为子任务
		if (m_ChildGraphTask.Num() > 0)
		{
			for (auto GraphTaskItem : m_ChildGraphTask)
			{
				GraphTaskItem->Unlock(); // 唤醒子任务
				MyCompletionGraphEvent->DontCompleteUntil(GraphTaskItem->GetCompletionEvent());
			}
			// 如有需要，可设法检测所有子任务是否都完成
		}

		// 创建并执行子任务，本处作为具体执行的任务
		MyCompletionGraphEvent->DontCompleteUntil(TGraphTask<FTaskGraph_SimpleTask>::CreateTask().ConstructAndDispatchWhenReady(m_ThreadName, m_GraphTaskDelegate));
		// UE_LOG(LogTemp, Warning, TEXT("Task[%s] End!"), *m_ThreadName);
	}
};

UCLASS()
class MISCELLANEOUSPROJECT_API ATaskGraphActor : public AActor
{
	GENERATED_BODY()
protected:
	virtual void BeginPlay() override;

public:
	// 创建任务
	UFUNCTION(BlueprintCallable)
	FTaskGraphItem CreateGraphTask(const FString& ThreadName, const TArray<FTaskGraphItem>& Prerequisites, const TArray<FTaskGraphItem>& ChildTasks, bool DispatchWhenReady);

	// 创建任务，CreateGraphTask 的简化
	UFUNCTION(BlueprintCallable)
	FTaskGraphItem CreateGraphTaskPure(const FString& ThreadName, bool DispatchWhenReady)
	{
		return CreateGraphTask(ThreadName, TArray<FTaskGraphItem>(), TArray<FTaskGraphItem>(), DispatchWhenReady);
	}

	// 唤醒挂起的任务
	UFUNCTION(BlueprintCallable)
	void TriggerGraphTask(FTaskGraphItem TaskGraphItem);

	// 用于任务中执行的回调函数
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void OnTaskFinished(const FString& message);

	// 测试用例
	/**	A0与A1执行完后执行B，B执行完后执行B0、B1，B0、B1执行完后执行C0、C1
	 *	A0-|    |->B0-|  |->C0
	 *	   |->B-|	  |->|
	 *	A1-|    |->B1-|  |->C1
	 **/
	UFUNCTION(BlueprintCallable)
	void ActiveTask();
private:
	FTaskGraphItem A0, A1, B, B0, B1, C0, C1;
};
